package com.echoplots.eureka.service;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Future;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.client.RestTemplate;

import com.echoplots.eureka.pojo.User;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheResult;
import com.netflix.hystrix.contrib.javanica.command.AsyncResult;

@Service("userService")
public class UserService {
    private Logger log = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private RestTemplate restTemplate;

/*    public User getUser(@PathVariable Long id) {
        return restTemplate.getForObject("http://Server-Provider/user/{id}", User.class, id);
    }*/

    
    /*
     * 上面的配置指定了命令的名称为getUserById，组名为userGroup，线程池名称为getUserThread。

通过设置命令组，Hystrix会根据组来组织和统计命令的告警、仪表盘等信息。默认情况下，Hystrix命令通过组名来划分线程池，即组名相同的命令放到同一个线程池里，如果通过threadPoolKey设置了线程池名称，则按照线程池名称划分
     */
    //getUser 改造
    @CacheResult//开启缓存注解  连续相同参数时调用多次则只调用一次
    @HystrixCommand(fallbackMethod = "getUserDefault", commandKey = "getUserById", groupKey = "userGroup",
            threadPoolKey = "getUserThread")
    public User getUser(@PathVariable Long id) {
       return restTemplate.getForObject("http://Server-Provider/user/{id}", User.class, id);
    }
    
/*    public User getUserDefault(Long id) {
        User user = new User();
        user.setName("defaultUser");
        user.setPassword("123456");
        return user;
    } */   
    
    //假如我们想指定某个异常不触发服务降级，可以使用@HystrixCommand注解的ignoreExceptions属性进行忽略
    //服务降级
    @HystrixCommand(fallbackMethod = "getUserDefault2", ignoreExceptions = {NullPointerException.class})
    public User getUserDefault(Long id) {
        String a = null;
        // 测试服务降级
        a.toString();
        User user = new User();
        user.setName("defaultUser");
        user.setPassword("123456");
        return user;
    }

    
    //方法抛出的异常信息，我们可以在服务降级的方法中使用Throwable对象获取
    public User getUserDefault2(Long id, Throwable e) {
        User user = new User();
        user.setName("defaultUser2");
        user.setPassword("123456");
        return user;
    }  
    
    
    public List<User> getUsers() {
        return this.restTemplate.getForObject("http://Server-Provider/user", List.class);
    }

    public String addUser() {
        User user = new User( "echoplots", "123456");
        HttpStatus status = this.restTemplate.postForEntity("http://Server-Provider/user", user, null).getStatusCode();
        if (status.is2xxSuccessful()) {
            return "新增用户成功";
        } else {
            return "新增用户失败";
        }
    }

    public void updateUser() {
        User user = new User( "echoplots", "123456");
        this.restTemplate.put("http://Server-Provider/user", user);
    }

    public void deleteUser(@PathVariable Long id) {
        this.restTemplate.delete("http://Server-Provider/user/{1}", id);
    }
    
    
    @HystrixCollapser(batchMethod = "findUserBatch", collapserProperties = {
            @HystrixProperty(name = "timerDelayInMilliseconds", value = "100")
    })
    public Future<User> findUser(Long id) {
        log.info("获取单个用户信息");
/*        return new AsyncResult<User>() {
            @Override
            public User invoke() {
                return restTemplate.getForObject("http://Server-Provider/user/{id}", User.class, id);
            }
        };*/
        
        //简化  上面注释服务不会被调用，所以简化
        return null;
    }

    @HystrixCommand
    public List<User> findUserBatch(List<Long> ids) {
        log.info("批量获取用户信息,ids: " + ids);
        User[] users = restTemplate.getForObject("http://Server-Provider/user/users?ids={1}", User[].class, StringUtils.join(ids, ","));
        return Arrays.asList(users);
    }
}